/**
 * A {@link Ext.ux.statusbar.StatusBar} plugin that provides automatic error
 * notification when the associated form contains validation errors.
 */
Ext.define('Ext.ux.statusbar.ValidationStatus', {
			extend : 'Ext.Component',
			requires : ['Ext.util.MixedCollection'],
			/**
			 * @cfg {String} errorIconCls The
			 *      {@link Ext.ux.statusbar.StatusBar#iconCls iconCls} value to
			 *      be applied to the status message when there is a validation
			 *      error.
			 */
			errorIconCls : 'x-status-error',
			/**
			 * @cfg {String} errorListCls The css class to be used for the error
			 *      list when there are validation errors.
			 */
			errorListCls : 'x-status-error-list',
			/**
			 * @cfg {String} validIconCls The
			 *      {@link Ext.ux.statusbar.StatusBar#iconCls iconCls} value to
			 *      be applied to the status message when the form validates.
			 */
			validIconCls : 'x-status-valid',

			/**
			 * @cfg {String} showText The
			 *      {@link Ext.ux.statusbar.StatusBar#text text} value to be
			 *      applied when there is a form validation error.
			 */
			showText : 'The form has errors (click for details...)',
			/**
			 * @cfg {String} hideText The
			 *      {@link Ext.ux.statusbar.StatusBar#text text} value to
			 *      display when the error list is displayed.
			 */
			hideText : 'Click again to hide the error list',
			/**
			 * @cfg {String} submitText The
			 *      {@link Ext.ux.statusbar.StatusBar#text text} value to be
			 *      applied when the form is being submitted.
			 */
			submitText : 'Saving...',

			// private
			init : function(sb) {
				var me = this;

				me.statusBar = sb;
				sb.on({
							single : true,
							scope : me,
							render : me.onStatusbarRender,
							beforedestroy : me.destroy
						});
				sb.on({
							click : {
								element : 'el',
								fn : me.onStatusClick,
								scope : me,
								buffer : 200
							}
						});
			},

			onStatusbarRender : function(sb) {
				var me = this, startMonitor = function() {
					me.monitor = true;
				};

				me.monitor = true;
				me.errors = Ext.create('Ext.util.MixedCollection');
				me.listAlign = (sb.statusAlign === 'right'
						? 'br-tr?'
						: 'bl-tl?');

				if (me.form) {
					me.formPanel = Ext.getCmp(me.form);
					me.basicForm = me.formPanel.getForm();
					me.startMonitoring();
					me.basicForm.on('beforeaction', function(f, action) {
								if (action.type === 'submit') {
									// Ignore monitoring while submitting
									// otherwise the field validation
									// events cause the status message to reset
									// too early
									me.monitor = false;
								}
							});
					me.basicForm.on('actioncomplete', startMonitor);
					me.basicForm.on('actionfailed', startMonitor);
				}
			},

			// private
			startMonitoring : function() {
				this.basicForm.getFields().each(function(f) {
							f
									.on('validitychange',
											this.onFieldValidation, this);
						}, this);
			},

			// private
			stopMonitoring : function() {
				this.basicForm.getFields().each(function(f) {
							f
									.un('validitychange',
											this.onFieldValidation, this);
						}, this);
			},

			// private
			onDestroy : function() {
				this.stopMonitoring();
				this.statusBar.statusEl.un('click', this.onStatusClick, this);
				this.callParent(arguments);
			},

			// private
			onFieldValidation : function(f, isValid) {
				var me = this, msg;

				if (!me.monitor) {
					return false;
				}
				msg = f.getErrors()[0];
				if (msg) {
					me.errors.add(f.id, {
								field : f,
								msg : msg
							});
				} else {
					me.errors.removeAtKey(f.id);
				}
				this.updateErrorList();
				if (me.errors.getCount() > 0) {
					if (me.statusBar.getText() !== me.showText) {
						me.statusBar.setStatus({
									text : me.showText,
									iconCls : me.errorIconCls
								});
					}
				} else {
					me.statusBar.clearStatus().setIcon(me.validIconCls);
				}
			},

			// private
			updateErrorList : function() {
				var me = this, msg, msgEl = me.getMsgEl();

				if (me.errors.getCount() > 0) {
					msg = ['<ul>'];
					this.errors.each(function(err) {
								msg.push('<li id="x-err-', err.field.id,
										'"><a href="#">', err.msg, '</a></li>');
							});
					msg.push('</ul>');
					msgEl.update(msg.join(''));
				} else {
					msgEl.update('');
				}
				// reset msgEl size
				msgEl.setSize('auto', 'auto');
			},

			// private
			getMsgEl : function() {
				var me = this, msgEl = me.msgEl, t;

				if (!msgEl) {
					msgEl = me.msgEl = Ext.DomHelper.append(Ext.getBody(), {
								cls : me.errorListCls
							}, true);
					msgEl.hide();
					msgEl.on('click', function(e) {
								t = e.getTarget('li', 10, true);
								if (t) {
									Ext.getCmp(t.id.split('x-err-')[1]).focus();
									me.hideErrors();
								}
							}, null, {
								stopEvent : true
							}); // prevent anchor click navigation
				}
				return msgEl;
			},

			// private
			showErrors : function() {
				var me = this;

				me.updateErrorList();
				me.getMsgEl().alignTo(me.statusBar.getEl(), me.listAlign)
						.slideIn('b', {
									duration : 300,
									easing : 'easeOut'
								});
				me.statusBar.setText(me.hideText);
				me.formPanel.body.on('click', me.hideErrors, me, {
							single : true
						}); // hide if the user clicks directly into the form
			},

			// private
			hideErrors : function() {
				var el = this.getMsgEl();
				if (el.isVisible()) {
					el.slideOut('b', {
								duration : 300,
								easing : 'easeIn'
							});
					this.statusBar.setText(this.showText);
				}
				this.formPanel.body.un('click', this.hideErrors, this);
			},

			// private
			onStatusClick : function() {
				if (this.getMsgEl().isVisible()) {
					this.hideErrors();
				} else if (this.errors.getCount() > 0) {
					this.showErrors();
				}
			}
		});